package org.phalanx.servlet.webmessages;

import java.util.ArrayList;
import java.util.Iterator;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.phalanx.map.MapCoordinates;
import org.phalanx.messenging.AbstractMessage;
import org.phalanx.server.PhalanxServer;
import org.phalanx.server.ServerCache.CacheManager;
import org.phalanx.server.ServerCache.Cacheable;
import org.phalanx.server.game.GameMove;
import org.phalanx.server.game.GameState;
import org.phalanx.server.game.PhalanxBattleRPGEngine;
import org.phalanx.server.game.PhalanxGameListInfoMessage;
import org.phalanx.server.game.PhalanxGameManager;
import org.phalanx.server.game.PhalanxGamePlayer;
import org.phalanx.server.game.PhalanxGameSettings;
import org.phalanx.server.game.PhalanxGameTurnTimer;
import org.phalanx.server.game.PhalanxMapCacheWrapper;
import org.phalanx.server.game.PhalanxPlayerState;
import org.phalanx.server.game.TimerCacheWrapper;
import org.phalanx.server.user.PhalanxUser;
import org.phalanx.servlet.websession.GameFeed;
import org.phalanx.servlet.websession.JoinFeed;
import org.phalanx.servlet.websession.ServletAuthenticatorManager;
import org.phalanx.servlet.websession.UserWebSession;
import org.phalanx.servlet.websession.UserWebSessionManager;

public class PhalanxGameContext implements WebMessageable {
	public static final String CONTEXT = "game";
	public static final String ACTION = "action";
	public static final String GAMEID = "gameid";
	private PhalanxServer pServer;

	public PhalanxGameContext(PhalanxServer pServer){
		this.pServer = pServer;
	}
	@Override
	public void onContextLoadable(String context, Cookie authCookie,
			HttpServletRequest req, HttpServletResponse resp) {
		if (context.equals(CONTEXT)){
			ServletAuthenticatorManager s = new ServletAuthenticatorManager(pServer);

			if (authCookie != null && s.authenticate(authCookie) != null){
				String action = req.getParameter(ACTION);
				Integer gameId = req.getParameter(GAMEID) == null ? null : Integer.valueOf(req.getParameter(GAMEID));

				CacheManager cacheMgr = pServer.getCacheManager();
				PhalanxGameManager gMgr = new PhalanxGameManager(cacheMgr);
				PhalanxUser u = (PhalanxUser)pServer.getCacheManager().getElement("TokenSessionCache", authCookie.getValue());

				if (u != null){
					if (action.equals("confirmsettings")){
						// Requests to join the gameroom
						// if the user is already joined this does the same action is getstate for current turn
						// and get users
						String playerAlias = req.getParameter("gamealias");
						String teamColorStr = req.getParameter("team");
						String buildPointX = req.getParameter("buildpointx");
						String buildPointY = req.getParameter("buildpointy");

						if (teamColorStr != null && buildPointX != null && buildPointY != null){
							Integer teamColorInt = Integer.valueOf(teamColorStr);
							playerAlias = playerAlias == null ? u.getUserName() : playerAlias;

							PhalanxGamePlayer playerX = new PhalanxGamePlayer();
							playerX.setUserId(u.getId());
							playerX.setGameAlias(playerAlias);
							playerX.setNationstatus(0);
							playerX.setTeamColor(teamColorInt);
							playerX.setWealth(0);
							playerX.setBuildPoint(new MapCoordinates(Integer.valueOf(buildPointX), Integer.valueOf(buildPointY)));

							JoinFeed jFeed = (JoinFeed)cacheMgr.getElement("JoinFeedCache", gameId);

							if (jFeed != null && jFeed.getUsers().contains(u.getId())){
								jFeed.addPlayerStateSettings(playerX);
							}

							//								// Joined up
							//								GameFeed gFeed = (GameFeed)cacheMgr.getElement("GameFeedCache", gameId);
							//								if (gFeed == null){
							//									gFeed = new GameFeed(gameId);
							//									cacheMgr.setElement("GameFeedCache", gameId, gFeed);
							//								}
							//								gFeed.addUserToFeed(u.getId());
							//							} else {
							//								// Error
							//							}


						}
						// gMgr.joinGame();
					} else if (action.equals("joingamefeed")){
						PhalanxPlayerState pState = (PhalanxPlayerState)cacheMgr.getElement("PlayerStateCache", gameId);

						if (pState.hasPlayer(u.getId())){
							GameFeed gFeed = (GameFeed)cacheMgr.getElement("GameFeedCache", gameId);
							if (gFeed == null){
								gFeed = new GameFeed(gameId);
								cacheMgr.setElement("GameFeedCache", gameId, gFeed);
							}
							gFeed.addUserToFeed(u.getId());
							gMgr.sendGameStateToUser(gameId, u.getId());
						}
					} else if (action.equals("leavegamefeed")){
						// Requests to leave gameroom but not the game
						// Player won't get feed updates until they rejoin
					} else if (action.equals("leavegame")){
						// Leaves the game feed and the game itself
					} else if (action.equals("getstate")){
						// Gets the user's state from any turn or just re-requests it from current
					} else if (action.equals("setaction")){
						// Sends an action to the game
					} else if (action.equals("endturn")){
						// For games with a turn based element to it
						gMgr.endGameTurnForPlayer(gameId, u.getId());
					} else if (action.equals("sendmsg")){
						// Sends a chat or private message
					} else if (action.equals("getplayers")){
						// gets other players names, game aliases, and public statisics
						// If the requesting player is a member of the game they may get additional info
					} else if (action.equals("getgamelist")){
						String order = req.getParameter("listorder");
						String criteria = req.getParameter("criteria");
						String criteriaMatch = req.getParameter("match");
						String archivedGames = req.getParameter("includearchived");
						String startIndexStr = req.getParameter("startindex");
						boolean includeArchived = false;
						Integer startIndex = 0;

						if (startIndexStr != null){
							startIndex = Integer.valueOf(startIndexStr);
						}

						if (archivedGames != null && archivedGames.equals("yes")){
							includeArchived = true;
						}

						ArrayList<PhalanxGameSettings> gList = gMgr.getGameList(order, criteria, 
								criteriaMatch, includeArchived, startIndex);

						UserWebSession session = (UserWebSession)cacheMgr.getElement("UserWebFeedCache", u.getId());

						PhalanxGameListInfoMessage infoMsg = new PhalanxGameListInfoMessage();
						infoMsg.addPhalanxGame(gList);

						session.sendMessage(infoMsg);
					}
					else if (action.equals("pause")){
						// requests to pause the game
						// during a pause the timer is stopped and all turns are rejected
						gMgr.pauseGame(u.getId(), gameId, true);
					} else if (action.equals("unpause")){
						// unpauses the game 
						gMgr.pauseGame(u.getId(), gameId, false);
					} else if (action.equals("creategame")){
						String gameName = req.getParameter("gamename");
						String gameMap = req.getParameter("mapname");
						Integer numberOfPlayers = Integer.valueOf(req.getParameter("maxplayers"));
						Integer turnMode = Integer.valueOf(req.getParameter("turnmode"));
						Integer timer = req.getParameter("timer") == null ? null : Integer.valueOf(req.getParameter("timer"));

						PhalanxGameSettings settings = new PhalanxGameSettings();
						settings.setGameCreatorId(u.getId());
						settings.setGameName(gameName);
						settings.setMapName(gameMap);
						settings.setNumberOfPlayers(numberOfPlayers);
						settings.setTurnMode(turnMode);
						settings.setTurnTime(timer);

						AbstractMessage createGameAcknowledged = new AbstractMessage();
						createGameAcknowledged.setMessageHeader("creategame");


						if (gMgr.createNewGame(settings, u.getId())){
							// if the game gets created
							// and everything checks out
							// create the game engine cache and the player timer

							PhalanxMapCacheWrapper gameMapWrap = (PhalanxMapCacheWrapper)cacheMgr.getElement("PhalanxMapCache", settings.getMapName());
							PhalanxBattleRPGEngine rpgEngine = new PhalanxBattleRPGEngine(settings.getId(), gameMapWrap.getMap());
							cacheMgr.setElement("GameEngineCache", settings.getId(), rpgEngine);

							PhalanxGameTurnTimer pTimer = new PhalanxGameTurnTimer(settings.getId());
							pTimer.setPaused(true);
							cacheMgr.setElement("PlayerTurnTimer", settings.getId(), new TimerCacheWrapper(pTimer));

							//							GameFeed newFeed = new GameFeed(settings.getId());
							//							cacheMgr.setElement("GameFeedCache", settings.getId(), newFeed);

							JoinFeed jFeed = new JoinFeed(settings.getId(), u.getId());
							//jFeed.addUserToFeed(u.getId());
							cacheMgr.setElement("JoinFeedCache", settings.getId(), jFeed);

							createGameAcknowledged.setToMessage("status", "success");
							createGameAcknowledged.setToMessage("gameid", settings.getId().toString());
						} else {
							createGameAcknowledged.setToMessage("status", "fail");
						}

						UserWebSession session = (UserWebSession)cacheMgr.getElement("UserWebFeedCache", u.getId());
						session.sendMessage(createGameAcknowledged);

					} else if (action.equals("lockgame")){

					} else if (action.equals("joinpregame")){
						// This is where users join a "joinfeed"
						// a pre-game feed where users set up their options
						// before joining an actual game and setting up playerstates

						PhalanxGameSettings settings = (PhalanxGameSettings)cacheMgr.getElement("GameListCache", gameId);
						AbstractMessage msg = new AbstractMessage();
						msg.setMessageHeader("joinfeed");
						
						if (settings != null && !gMgr.isGameStarted(gameId)){
							JoinFeed jFeed = (JoinFeed)cacheMgr.getElement("JoinFeedCache", gameId);

							if (jFeed != null){
								jFeed.addUserToFeed(u.getId());

								if (!jFeed.getUsers().contains(u.getId())){
									// Fail
								}
							}
						}
					}

					else if (action.equals("forcestartgame")){
						// The facilitator of the game can jump start the game timer and everything
						PhalanxGameSettings settings = (PhalanxGameSettings)cacheMgr.getElement("GameListCache", gameId);
						//						PhalanxPlayerState pState = (PhalanxPlayerState)cacheMgr.getElement("PlayerStateCache", gameId);

						PhalanxPlayerState pState = new PhalanxPlayerState(gameId);
						JoinFeed jFeed = (JoinFeed)cacheMgr.getElement("JoinFeedCache", gameId);

						// Set the players into a player state
						if (jFeed != null){
							Iterator<PhalanxGamePlayer> i = jFeed.getPlayerStates().getPlayerList().iterator();

							while (i.hasNext()){
								PhalanxGamePlayer tPlayer = i.next();

								pState.addPlayerToList(tPlayer);
							}

							cacheMgr.setElement("PlayerStateCache", gameId, pState);

							// Destroy join feed
							jFeed.clearFeed();
							cacheMgr.removeElement("JoinFeedCache", gameId);

							// Set game manager to start the game
							// Create game feed

							GameFeed feed = new GameFeed(gameId);
							cacheMgr.setElement("GameFeedCache", gameId, feed);

							gMgr.startNewGame(gameId, u.getId());

						} else if (action.equals("destroygame")){
							if(gMgr.removeCurrentGame(gameId, u.getId())){
								GameFeed feed = (GameFeed)cacheMgr.getElement("GameFeedCache", gameId);

								if (feed != null){
									feed.clearFeed();
									cacheMgr.removeElement("GameFeedCache", gameId);
								}
								// Acknowledge game removal here
							} else {
								// Something went wrong
							}
						} else if (action.equals("actionmove")){
							Integer moveType = Integer.valueOf(req.getParameter("movetype"));
							Integer turnId = Integer.valueOf(req.getParameter("turnid"));
							String coor1x = req.getParameter("x1");
							String coor1y = req.getParameter("y1");
							String coor2x = req.getParameter("x2");
							String coor2y = req.getParameter("y2");

							Integer unitId1 = Integer.valueOf(req.getParameter("unitid1"));

							String unitId2 = req.getParameter("unitid2");
							String attributeName = req.getParameter("attrname");
							String attributeValue = req.getParameter("attrvalue");

							GameMove newMove = new GameMove();
							newMove.setTurn(turnId);
							newMove.setUserId(u.getId());
							newMove.setActionType(moveType);
							newMove.setAttributeName(attributeName);
							newMove.setAttributeValue(attributeValue);
							newMove.setUnitid1(unitId1);

							MapCoordinates c1 = new MapCoordinates(Integer.valueOf(coor1x), Integer.valueOf(coor1y));

							newMove.setCoordinates1(c1);

							if (coor2x != null && coor2y != null){
								MapCoordinates c2 = new MapCoordinates(Integer.valueOf(coor2x), Integer.valueOf(coor2y));
								newMove.setCoordinates2(c2);
							}

							if (unitId2 != null){
								newMove.setUnitid2(Integer.valueOf(unitId2));
							}

							// Game Manager should accept the move at this point
							gMgr.setGameMove(gameId, newMove);
						}
					}
				}
			}
		}
	}
}
